package naga.x.platform2.channel.s399;

import java.util.Map;
import java.util.TreeMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import naga.x.platform2.app.Channel;
import naga.x.platform2.app.model.GameServer;
import naga.x.platform2.app.model.Recharge;
import naga.x.platform2.app.model.RechargeTemplate;
import naga.x.platform2.app.support.GameServerSupport;
import naga.x.platform2.app.support.RechargeSupport;
import naga.x.platform2.channel.s399.support.S399Api;
import naga.x.platform2.channel.s399.support.S399Api.Code;
import naga.x.platform2.channel.s399.support.S399Api.PayInfo;
import naga.x.platform2.channel.s399.support.S399Api.SDKCode;
import naga.x.platform2.channel.s399.support.S399Config;
import naga.x.platform2.support.RequestPath;
import naga.x.platform2.utils.HttpUtils;
import naga.x.platform2.utils.NumberUtils;

/**
 * 4399
 * @see doc/4399.html
 * @author yang.li
 *
 */
@Controller
public class S399Controller {
	
	@Autowired
	private S399Config config;
	@Autowired
	private S399Api api;
	@Autowired
	private RechargeSupport support;
	@Autowired
	private GameServerSupport gameServers;
	
	private static Channel channel = Channel.S399;
	
	public static final Logger LOG = LoggerFactory.getLogger(S399Controller.class);
	
	@RequestMapping(path = RequestPath.S399_LOGIN)
	public String login(String gameId, String userId, String userName, String time, String sign) {
//		"gameId=%stime=%suserId=%suserName=%s%s", $gameId, $time, $userId, $userName, $callbackKey)
		if (System.currentTimeMillis() / 1000 - NumberUtils.parseLong(time) > config.getLoginTimeout()) {
			return api.createLoginRedirectUrl(S399Api.Code.TIMEOUT);
		}
		
		Map<String, String> params = new TreeMap<String, String>();
		params.put("gameId", gameId);
		params.put("userId", userId);
		params.put("userName", userName);
		params.put("time", time);
		if (!api.makeSign(params).equals(sign)) {
			return api.createLoginRedirectUrl(S399Api.Code.SIGN_ERROR);
		}
		return api.createLoginRedirectUrl(S399Api.Code.SUCC, userId, userName);
	}
	
	@RequestMapping(path = RequestPath.S399_PAY, produces = "application/json; charset=UTF-8")
	@ResponseBody
	public Object pay(Integer sid, Long pid, Integer product) {
		GameServer gs = gameServers.get(sid);
		if (gs == null) {
			return S399Api.createOrderResponse(Code.SERVER_NOT_FOUND);
		}
		if (pid == null) {
			return S399Api.createOrderResponse(Code.PLAYER_ID_ERROR);
		}
		RechargeTemplate template = support.getTemplate(product);
		if (template == null) {
			return S399Api.createOrderResponse(Code.RECHARGE_PRODUCT_NOT_FOUND);
		}
		return S399Api.createOrderResponse(Code.SUCC, sid, pid, template);
	}
	
	@RequestMapping(path = RequestPath.S399_PAY_CALLBACK, method = RequestMethod.POST, produces = "application/json; charset=UTF-8")
	@ResponseBody
	public Object payCallback(String orderId, String gameId, String userId, String userName,
								Integer money, Integer gameMoney, String mark, Integer server, String time,
								String ext, String sign, String test) {
//		md5(sprintf("gameId=%smark=%smoney=%sorderId=%sserver=%stime=%suserId=%suserName=%s%s", $gameId, $mark, $money, $orderId, $server, $time, $userId, $userName, $callbackKey));
		// gameMoney, ext, test不参与校验
		String ip = HttpUtils.getRequestAddr();
		if (System.currentTimeMillis() / 1000 - NumberUtils.parseLong(time) > config.getPayTimeout()) {
			LOG.info("[4399 PAY ERR]ORDERID[{}]GAMEID[{}]UID[{}]UNAME[{}]MONEY[{}]GMONEY[{}]MARK[{}]SERVER[{}]TIME[{}]EXT[{}]SIGN[{}]TEST[{}]SIGN2[{}]IP[{}]CAUSE[TIMEOUT]",
					orderId, gameId, userId, userName, money, gameMoney, mark, server, time, ext, sign, test, null, ip);
			return SDKCode.TIMEOUT.toString();
		}
		Map<String, String> params = new TreeMap<>();
		params.put("gameId", S399Api.valueFilter(gameId));
		params.put("mark", S399Api.valueFilter(mark));
		params.put("money", S399Api.valueFilter(money));
		params.put("orderId", S399Api.valueFilter(orderId));
		params.put("server", S399Api.valueFilter(server));
		params.put("time", S399Api.valueFilter(time));
		params.put("userId", S399Api.valueFilter(userId));
		params.put("userName", S399Api.valueFilter(userName));
		String s = api.makeSign(params);
		if (!s.equals(sign)) {
			LOG.info("[4399 PAY ERR]ORDERID[{}]GAMEID[{}]UID[{}]UNAME[{}]MONEY[{}]GMONEY[{}]MARK[{}]SERVER[{}]TIME[{}]EXT[{}]SIGN[{}]TEST[{}]SIGN2[{}]IP[{}]CAUSE[SIGNERR]",
									orderId, gameId, userId, userName, money, gameMoney, mark, server, time, ext, sign, test, s, ip);
			return SDKCode.SIGN_ERROR.toString();
		}
		PayInfo payInfo = S399Api.parsePayInfo(ext);
		GameServer gs = gameServers.get(payInfo.serverId);
		if (gs == null) {
			LOG.info("[4399 PAY ERR]ORDERID[{}]GAMEID[{}]UID[{}]UNAME[{}]MONEY[{}]GMONEY[{}]MARK[{}]SERVER[{}]TIME[{}]EXT[{}]SIGN[{}]TEST[{}]SIGN2[{}]IP[{}]CAUSE[GSERR]",
					orderId, gameId, userId, userName, money, gameMoney, mark, server, time, ext, sign, test, s, ip);
			return SDKCode.GAME_SERVER_NOT_FOUND.toString();
		}
		if (config.getUserWhitelist().contains(userId) && !gs.isTest()) {
			LOG.info("[4399 PAY ERR]ORDERID[{}]GAMEID[{}]UID[{}]UNAME[{}]MONEY[{}]GMONEY[{}]MARK[{}]SERVER[{}]TIME[{}]EXT[{}]SIGN[{}]TEST[{}]SIGN2[{}]IP[{}]CAUSE[TESTACC]",
					orderId, gameId, userId, userName, money, gameMoney, mark, server, time, ext, sign, test, s, ip);
			return SDKCode.USER_NOT_FOUND.toString();
		}
		RechargeTemplate product = support.getTemplate(payInfo.productId);
		if (product == null) {
			LOG.info("[4399 PAY ERR]ORDERID[{}]GAMEID[{}]UID[{}]UNAME[{}]MONEY[{}]GMONEY[{}]MARK[{}]SERVER[{}]TIME[{}]EXT[{}]SIGN[{}]TEST[{}]SIGN2[{}]IP[{}]CAUSE[PRODUCTERR]",
					orderId, gameId, userId, userName, money, gameMoney, mark, server, time, ext, sign, test, s, ip);
			return SDKCode.UNKOWN_ERROR.toString();
		}
		if (money != product.getPrice()) {
			LOG.info("[4399 PAY ERR]ORDERID[{}]GAMEID[{}]UID[{}]UNAME[{}]MONEY[{}]GMONEY[{}]MARK[{}]SERVER[{}]TIME[{}]EXT[{}]SIGN[{}]TEST[{}]SIGN2[{}]IP[{}]CAUSE[MONEYERR]",
					orderId, gameId, userId, userName, money, gameMoney, mark, server, time, ext, sign, test, s, ip);
			return SDKCode.MONEY_ERROR.toString();
		}
		if (!api.isValidIp(ip)) {
			LOG.info("[4399 PAY ERR]ORDERID[{}]GAMEID[{}]UID[{}]UNAME[{}]MONEY[{}]GMONEY[{}]MARK[{}]SERVER[{}]TIME[{}]EXT[{}]SIGN[{}]TEST[{}]SIGN2[{}]IP[{}]CAUSE[IPERR]",
					orderId, gameId, userId, userName, money, gameMoney, mark, server, time, ext, sign, test, s, ip);
			return SDKCode.IP_ILLEGAL.toString();
		}
		Recharge entity = new Recharge(channel.prefix + orderId, payInfo.playerId, payInfo.serverId, money, product.getStone(), product.getId(), channel.name);
		entity.setAttach(mark); // 我方订单号
		entity.setChannelUid(channel.withPrefix(userId));
		boolean succ = support.offer(entity);
		LOG.info("[4399 PAY SUCC]ORDERID[{}]GAMEID[{}]UID[{}]UNAME[{}]MONEY[{}]GMONEY[{}]MARK[{}]SERVER[{}]TIME[{}]EXT[{}]SIGN[{}]TEST[{}]SIGN2[{}]IP[{}]SUCC[{}]",
				orderId, gameId, userId, userName, money, gameMoney, mark, server, time, ext, sign, test, s, ip, succ ? 1 : 0);
		return SDKCode.SUCC.toString();
	}
	
}
